#include "lucc.h"
#include "sn.h"

/*********************************************************
 *
 * GLOBAL
 *
 ********************************************************/

#define CMD_OK					0
#define CMD_QUIT				1
#define CMD_NULL				-1
#define CMD_ERR					-2
#define CMD_UNKNOWN				-3
#define CMD_INVALID				-4
#define CMD_NOPASS				-5
#define CMD_SHORTPASS				-6


typedef int (*cmd_cb_t) (char *arg);

typedef struct {
	char *cmd;
	char *desc;
	cmd_cb_t cb;
} cmd_t;


void cmd_res(int res);
int cmd_help(char *arg);
int cmd_quit(char *arg);
int cmd_machine(char *arg);
int cmd_save(char *arg);
int cmd_load(char *arg);
int cmd_show(char *arg);
int cmd_password(char *arg);
int cmd_fax_number(char *arg);
int cmd_deadline(char *arg);
int cmd_free(char *arg);

static license_data_t license_data;
static license_t local;
static char PASSWORD[256];

static cmd_t g_cmd[] = {
	{	"help",				"help menu",			&cmd_help		},
	{	"quit",				"quit",				&cmd_quit		},
	{	"machine <file>",		"load machine code",		&cmd_machine		},
	{	"save <file>",			"save license",			&cmd_save		},
	{	"load <file>",			"load license",			&cmd_load		},
	{	"show",				"show license",			&cmd_show		},
	{	"password",			"set password",			&cmd_password		},
	{	"fax <number>",			"set fax number",		&cmd_fax_number		},
	{	"deadline <yyyymmdd>",		"set deadline",			&cmd_deadline		},
	{	"free",				"set license unlimited",	&cmd_free		},
	{	NULL,				NULL,				NULL			}
};

/*********************************************************
 *
 * CMD
 *
 ********************************************************/

static int cmd_intarg(char *arg, int *num)
{
	int ret;

	if(arg == NULL || arg[0] == '\0')
		return CMD_INVALID;

	ret = sscanf(arg, "%d", num);
	if(ret != 1)
		return CMD_INVALID;

	return CMD_OK;
}

static int cmd_strarg(char *arg, char *str, int len)
{
	if(arg == NULL || arg[0] == '\0')
		return CMD_INVALID;

	while(arg[0] == ' ' || arg[0] == '\t')
		arg ++;

	if(arg[0] == '\0')
		return CMD_INVALID;

	str_ncopy(str, arg, len);

	return CMD_OK;
}

static int cmd_filearg(char *arg, char *file, int len)
{
	int ret;

	ret = cmd_strarg(arg, file, len);
	if(ret != CMD_OK)
		return ret;

	if(access(file, R_OK | W_OK))
		return CMD_INVALID;

	return CMD_OK;
}

int cmd_help(char *arg)
{
	int i;

	printf("\n");

	for(i = 0 ; g_cmd[i].cmd ; i ++)
		printf("%-20s\t\t%s\n", g_cmd[i].cmd, g_cmd[i].desc);

	return CMD_OK;
}

int cmd_quit(char *arg)
{
	printf("\n- BYE\n");
	printf("\n");

	exit(0);

	return CMD_QUIT;
}

int cmd_machine(char *arg)
{
	char machine_code[4096];
	char machine_str[4096];
	char file[128];
	int len;
	int ret;

	if(PASSWORD[0] == '\0')
		return CMD_NOPASS;

	ret = cmd_filearg(arg, file, sizeof(file));
	if(ret != CMD_OK)
		return ret;

	len = file_read(file, machine_code, sizeof(machine_code));
	if(len <= 0)
		return CMD_ERR;

	ret = sn_private_dec(PASSWORD, machine_code, len, machine_str, sizeof(machine_str));
	if(ret <= 0)
		return CMD_ERR;

	printf("\n");
	printf("%s", machine_str);

	license_set(&local, machine_str);

	return CMD_OK;
}

int cmd_load(char *arg)
{
	char data_buf[4096];
	char buf[4096];
	char file[128];
	int len;
	int ret;

	ret = cmd_filearg(arg, file, sizeof(file));
	if(ret != CMD_OK)
		return ret;

	len = file_read(file, buf, sizeof(buf));
	if(len <= 0)
		return CMD_INVALID;

	len = sn_public_dec(buf, len, data_buf, sizeof(data_buf));
	if(len <= 0)
		return CMD_ERR;

	license_set(&local, data_buf);

	sn_load_data(data_buf, &license_data);
	
	cmd_set_data();

	return CMD_OK;
}

int cmd_save(char *arg)
{
	char data_buf[4096];
	char buf[4096];
	char file[128];
	int len;
	int ret;

	if(PASSWORD[0] == '\0')
		return CMD_NOPASS;

	ret = cmd_strarg(arg, file, sizeof(file));
	if(ret != CMD_OK)
		return ret;

//	license_default(&local);

	cmd_set_data();

	ret = license_show(&local, data_buf, sizeof(data_buf));
	if(ret <= 0)
		return CMD_ERR;
	
	len = sn_private_enc(PASSWORD, data_buf, strlen(data_buf), buf, sizeof(buf));
	if(len <= 0) {
		return CMD_ERR;
	}

	ret = file_write(file, buf, len);
	if(ret <= 0)
		return CMD_ERR;
	
	return CMD_OK;
}

int cmd_show(char *arg)
{
	char buf[4096];
	printf("\n");

	license_show(&local, buf, sizeof(buf));
	printf("%s", buf);

	return CMD_OK;
}

int cmd_password(char *arg)
{
	char *pass;

	printf("\n");

	PASSWORD[0] = '\0';

	while(1) {
		pass = getpass("input password: ");
		if(pass == NULL || pass[0] == '\0')
			continue;

		str_copy(PASSWORD, pass);
		str_trim(PASSWORD);
		str_rtrim(PASSWORD);

		if(strlen(PASSWORD) < 4) {
			cmd_res(CMD_SHORTPASS);
			printf("\n");
			continue;
		}

		if(PASSWORD[0])
			break;
	}

	return CMD_OK;
}

int cmd_free(char *arg)
{
	license_data.fax_number = -1;
	license_data.deadline = 20301231;

	cmd_set_data();

	return CMD_OK;
}

static void cmd_prompt()
{
	printf("\nLuCC.SN > ");
	fflush(stdout);
}

static int cmd_get(char *cmd, int size)
{
	char *s;

	memset(cmd, 0, size);

	s = fgets(cmd, size - 1, stdin);
	if(s == NULL)
		return CMD_QUIT;

	str_trim(cmd);
	str_rtrim(cmd);

	return CMD_OK;
}

static int cmd_run(char *cmd)
{
	char cmd0[256];
	char *arg;
	char *p;
	int i;

	if(cmd[0] == '\0')
		return CMD_NULL;

	arg = strchr(cmd, ' ');
	if(arg) {
		arg[0] = '\0';
		arg ++;
		str_trim(arg);
	}

	for(i = 0 ; g_cmd[i].cmd ; i ++) {
		str_copy(cmd0, g_cmd[i].cmd);
		p = strchr(cmd0, ' ');
		if(p)
			p[0] = '\0';

		if(strcmp(cmd0, cmd))
			continue;

		return (g_cmd[i].cb)(arg);
	}

	return CMD_UNKNOWN;
}

void cmd_res(int res)
{
	switch(res) {
		case CMD_OK:
			printf("\n- OK\n");
			break;

		case CMD_ERR:
			printf("\n- ERR\n");
			break;

		case CMD_UNKNOWN:
			printf("\n- UNKNOWN, type help for more commands\n");
			break;

		case CMD_INVALID:
			printf("\n- INVALID, not a valid parameter\n");
			break;

		case CMD_NOPASS:
			printf("\n- ERR, need a password\n");
			break;

		case CMD_SHORTPASS:
			printf("\n- ERR, password is too short\n");
			break;
	}
}

static void cmd()
{
	int ret = CMD_OK;
	char cmd[80];

	while(ret != CMD_QUIT) {
		cmd_prompt();

		ret = cmd_get(cmd, sizeof(cmd));
		if(ret == CMD_QUIT)
			break;

		ret = cmd_run(cmd);

		cmd_res(ret);
	}

	printf("\n");
	printf("\n- BYE\n");
	printf("\n");
}

/*********************************************************
 *
 * CMD LINE
 *
 ********************************************************/

int cmd_line(int argc, char *argv[])
{
	char *mc_file = "";
	char *sn_file = "";
	int args = 0;
	int ret;
	int i;

	for(i = 1 ; i < argc - 1 ; i ++) {
		if(! strcmp(argv[i], "fax")) {
			license_data.fax_number = atoi(argv[i + 1]);
			i ++;
			args ++;
		} else if(! strcmp(argv[i], "deadline")) {
			license_data.deadline = atoi(argv[i + 1]);
			i ++;
			args ++;
		} else if(! strcmp(argv[i], "password")) {
			strcpy(PASSWORD, argv[i + 1]);
			i ++;
			args ++;
		} else if(! strcmp(argv[i], "machine")) {
			mc_file = argv[i + 1];
			i ++;
			args ++;
		} else if(! strcmp(argv[i], "save")) {
			sn_file = argv[i + 1];
			i ++;
			args ++;
		}
	}

	if(mc_file[0] && PASSWORD[0]) {
		ret = cmd_machine(mc_file);
		if(ret != CMD_OK)
			return -2;

		if(args != 5)
			return 0;
	}

	if(args != 5)
		return -1;

	ret = cmd_save(sn_file);
	if(ret != CMD_OK)
		return -3;

	return 0;
}

/*********************************************************
 *
 * MAIN
 *
 ********************************************************/

int main(int argc, char *argv[])
{
	sn_init();

	if(argc > 1)
		return cmd_line(argc, argv);

	cmd();

	return 0;
}
